﻿#include "stdafx.h"
#include "SocketDB.h"
#include "sqlite3.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <winsock2.h>
#include <afxmt.h>

const  char                   SPACECHAR[2] = {0,0};              //널문자 표현.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// TCP/IP용 보내기/받기 함수.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 보내기 함수.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
__inline BOOL  SEND(SOCKET sock, char * buf, const int nBufSize, int OPT)                            
{
	int nSendSize = 0;
	int nFillSize = 0;
	//int nErr = 0;
	while(TRUE)
	{
		nSendSize = send(sock,buf + nFillSize ,nBufSize - nFillSize,OPT);
		//SLOGINT(nSendSize);
		switch(nSendSize)
		{
		case -1:
			//nErr = WSAGetLastError();
			//SLOGINT(nErr);
			if( WSAGetLastError()  == WSAEWOULDBLOCK)
			{
				Sleep(100);
				continue;
			}
			else
			{
				return FALSE;
			}
		case 0:
			return FALSE;
		default:
			nFillSize += nSendSize;
			if( nFillSize >= nBufSize)
			{
				return TRUE;
			}
		}
	}
	return TRUE;
}					
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 받기 함수.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
__inline BOOL RECV(SOCKET sock, char * buf, const int nBufSize, int OPT)                            
{
	int nRecvSize = 0;
	int nFillSize = 0;
	int nErr;
	while(TRUE)
	{
		nRecvSize = recv(sock,(char*)buf + nFillSize, nBufSize - nFillSize,0);
		//SLOGINT(nRecvSize);
		switch(nRecvSize)
		{
		case -1:
			nErr = WSAGetLastError();
			//SLOGINT(nErr);
			//if( WSAGetLastError()  == WSAEWOULDBLOCK)
			if( nErr == WSAEWOULDBLOCK)
			{
				Sleep(100);
				continue;
			}
			else
			{
				return FALSE;
			}
		case 0:
			return FALSE;
		default:
			nFillSize += nRecvSize;
			if( nFillSize >= nBufSize)
			{
				return TRUE;
			}
		}
	}
	return TRUE;
}

//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 생성자/파괴자.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 생성자.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
CSocketDB::CSocketDB()
{
	SFUNC()
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 오버 로드 생성자.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
CSocketDB::CSocketDB(const int nIndex, sqlite3 *pFileSQLite,SOCKET sock, char *pszIP)
{
	SFUNC()
	//==================================================
	// 나의 인덱스 저장.
	//==================================================
	m_nMyIndex = nIndex;
	//==================================================
	// 변수 저장 
	//==================================================
	m_pSQLite = pFileSQLite;
	m_sock = INVALID_SOCKET;
	m_sock = sock;
	//==================================================
	// 사용자 정보 초기화.
	//==================================================
	memset(m_szIP,0,30);
	memset(m_szUser,0,30);
	m_nAuth = 0;
	//==================================================
	// IP 저장. 
	//==================================================
	memset(m_szIP,'\0',30);
	if( NULL != pszIP)
		memcpy(m_szIP,pszIP,strlen(pszIP));
	//==================================================
	// 현재 생성 시간 저장. 
	//==================================================
	m_opTime = time(NULL);
	//==================================================
	// 서버용 stmt 초기화.
	//==================================================
	for(int i = 0 ; i < STMT_SVRCOUNT ;i ++)
	{
		m_stmt[i] = NULL;
	}
	//==================================================
	// 컬럼 카운트.
	//==================================================
	m_nColCount = 0;
	//==================================================
	// 자신의 Begin 유무 상태
	//==================================================
	m_bBegin = FALSE;
	m_pRead = NULL;

}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 파괴자.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
CSocketDB::~CSocketDB()
{
	SFUNC()
	//==================================================
	// 모든 프로토콜 지움.
	//==================================================
	for(int i = 0 ; i < STMT_SVRCOUNT ; i++)
	{
		if( NULL == m_stmt[i])
			break ;
		if( NULL != m_stmt[i]->m_pStmt)  //데이터셋 포인터.
		{
			sqlite3_finalize(m_stmt[i]->m_pStmt);
		}
		SFREE(m_stmt[i]->m_pszError)
		delete m_stmt[i];
	}
	//==================================================
	// 본 클래스에서 Begin을 수행 했다면, Commit한 후에 빠져 나간다.
	//==================================================
	if(( TRUE == m_bBegin))
	{
		gDoCommit();
	}
	//==================================================
	// Read Only 닫기.
	//==================================================
	if( m_pRead != NULL)
		sqlite3_close(m_pRead);
	//==================================================
	// 소켓 닫기.
	//==================================================
	CloseSocketDB();
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Read Only DB Connection 열기/만약 필요하다면, 사용자 함수 등록/현재는 Connection만.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
BOOL CSocketDB::OpenReadFile(char * pFileName)
{
	SFUNC()
	if ( SQLITE_OK !=sqlite3_open_v2(pFileName,&m_pRead,SQLITE_OPEN_READONLY,NULL))
	{
     	return FALSE;
    }
	if( SQLITE_OK != sqlite3_exec(m_pRead,"PRAGMA read_uncommitted=TRUE",NULL,NULL,NULL))
	{
		sqlite3_close(m_pRead);
		m_pRead = NULL;
		return FALSE;
	}
	return TRUE;
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 현재, 작업 내용 알아내기. ==>모니터링용 함수.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::GetMonInfo(MON_INFO *info)
{
	SFUNC()
	memset(info,0,sizeof(MON_INFO));
	info->opTime = m_opTime;
	STRCPY(info->szIP,m_szIP,30);
	STRCPY(info->szUser,m_szUser,30);
	info->nAuth = m_nAuth;
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Send Welcom 메시지. 현재는 안쓰임. 나중에 쓰임.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::SendWelcom()
{
	SFUNC()
	PACKET_STRT Pack;
	RESETPACK(Pack);
	Pack.nIndex = 0;
	Pack.nItem = ITEM_ACCEPT;
	Pack.nStat = STAT_END;
	Pack.nReply = REPLY_CLIENT_OK;
	Pack.nDataLen = strlen("Connection is Success");
	memcpy(Pack.szData,"Connection is Success",Pack.nDataLen);
	SEND(m_sock, (char*)&Pack,  sizeof(PACKET_STRT) , 0);
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Close Socket.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 소켓 닫기.. 
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::CloseSocketDB()
{
	SFUNC()
	CLOSESOCKET(m_sock)
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 일정 시간 이상 지나면 닫기. 
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
BOOL CSocketDB::IfCloseSocketDB()
{
	SFUNC()
	time_t temptime = time(NULL);
	if((temptime - m_opTime) > g_nTimeout)
	{
		CLOSESOCKET(m_sock)
		return TRUE;
	}
	return FALSE;
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// DB Operation Function.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Execute SQL. 
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
BOOL CSocketDB::ExecuteSQL(const char *pszSQL)
{
	SFUNC()
	m_bBegin = gDoBegin();
	CS_LOCK()
	SFREE(m_stmt[m_nCurIndex]->m_pszError);
	int ret;
	ret = sqlite3_exec(m_pSQLite,pszSQL,NULL,NULL,&m_stmt[m_nCurIndex]->m_pszError);
	BOOL bResult;
	if( SQLITE_OK != ret)
	{
		printf("Excute Error:%s\n",m_stmt[m_nCurIndex]->m_pszError);
		SetErrorMsg(m_stmt[m_nCurIndex]->m_pszError);
		gWriteLog("%s%s","Fail To Execute:",pszSQL);
		bResult = FALSE;
	}
	else
	{
		gWriteArchive(m_stmt[m_nCurIndex]->m_szSQL);
		bResult = TRUE;
	}
	CS_UNLOCK()
	return bResult;
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Select Prepare. 
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
BOOL CSocketDB::SelectPrepare(const char *pszSQL) 
{
	SFUNC()
	m_stmt[m_nCurIndex]->m_nRow = 0;
	m_stmt[m_nCurIndex]->m_bIsEnd = TRUE;
	if( m_stmt[m_nCurIndex]->m_pStmt != NULL)
	{
		
		sqlite3_finalize(m_stmt[m_nCurIndex]->m_pStmt );
		m_stmt[m_nCurIndex]->m_pStmt = NULL;
	}
	int ret;
	ret = sqlite3_prepare( m_pRead, pszSQL, (int)strlen(pszSQL)+1, &m_stmt[m_nCurIndex]->m_pStmt,NULL);
	if( SQLITE_OK == ret)
	{
		m_stmt[m_nCurIndex]->m_nCol = sqlite3_column_count( m_stmt[m_nCurIndex]->m_pStmt );
		return TRUE;
	}
	else
	{
		SetErrorMsg((char*) sqlite3_errmsg(m_pRead));
		gWriteLog("%s%s","Fail To Select:",pszSQL);
		return FALSE;
	}
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Select 사용자 함수 사용. 
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
BOOL CSocketDB::SelectUserFunc(const char *pszSQL) 
{
	SFUNC()
	m_bBegin = gDoBegin();
	CS_LOCK()
	m_stmt[m_nCurIndex]->m_nRow = 0;
	m_stmt[m_nCurIndex]->m_bIsEnd = TRUE;
	if( m_stmt[m_nCurIndex]->m_pStmt != NULL)
	{
		sqlite3_finalize(m_stmt[m_nCurIndex]->m_pStmt );
		m_stmt[m_nCurIndex]->m_pStmt = NULL;
	}
	int ret;
	BOOL bResult = FALSE;
	ret = sqlite3_prepare( m_pSQLite, pszSQL, (int)strlen(pszSQL)+1, &m_stmt[m_nCurIndex]->m_pStmt,NULL);
	if(SQLITE_OK == ret)
	{

		ret = sqlite3_step(m_stmt[m_nCurIndex]->m_pStmt);
		if( (SQLITE_ROW == ret) || ( SQLITE_DONE == ret) )
		{
			bResult = TRUE;
		}
	}
	else
	{
		SetErrorMsg((char*) sqlite3_errmsg(m_pRead));
		gWriteLog("%s%s","Fail To User Func:",pszSQL);
	}
	if( m_stmt[m_nCurIndex]->m_pStmt != NULL)
	{
		sqlite3_finalize(m_stmt[m_nCurIndex]->m_pStmt );
		m_stmt[m_nCurIndex]->m_pStmt = NULL;
	}
	CS_UNLOCK()
	m_bBegin = gDoCommit();
	return bResult;
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 현재의 함수가 얼마나지연 되었는지 알아 낸다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
int CSocketDB::GetDelay()
{
	SFUNC()
	time_t temptime = time(NULL);
	return (int)(temptime - m_opTime);
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 에러에 대해서 문자열을 세팅.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::SetErrorMsg(char *pszError)
{
	SFUNC()
	memset(m_stmt[m_nCurIndex]->m_szError,'\0',1024);

	if( NULL != pszError)
		strncpy_s(m_stmt[m_nCurIndex]->m_szError,1023,pszError,min(1022,strlen(pszError)));
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 소켓에 쓰는 함수.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::WriteSock(const short nItem, const short nStat, const short nReply , 
							   const short nDataLen ,const char *pszData)
{
	SFUNC()
	if ( m_sock == INVALID_SOCKET )
		return;
	m_opTime = time(NULL);
	RESETPACK(m_Pack);
	m_Pack.nIndex = m_nCurIndex;
	m_Pack.nItem = nItem;
	m_Pack.nStat = nStat;
	m_Pack.nReply = nReply;
	m_Pack.nDataLen = nDataLen;
	memcpy(m_Pack.szData,pszData,nDataLen);
	SEND(m_sock, (char*)&m_Pack,  sizeof(PACKET_STRT) , 0);
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// SQL문을 현재의 STMT 객체에 더한다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::AddSQL()
{
	SFUNC()
	if(( m_stmt[m_nCurIndex]->m_nSize + m_Pack.nDataLen ) > 4096 )
		return;
	memcpy(m_stmt[m_nCurIndex]->m_szSQL + m_stmt[m_nCurIndex]->m_nSize,	m_Pack.szData,m_Pack.nDataLen);
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 데이터를 받았을 때, Main Loop에서 주기적으로 호출되는 함수.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
BOOL CSocketDB::DoJob() //데이터가 도착 했을 때, 주기적으로 호출 되는 함수.
{
	SFUNC()
	memset(&m_Pack,'\0',sizeof(m_Pack));
	//==================================================
	// 패킷 사이즈 결정.
	//==================================================
	if(FALSE == RECV(m_sock,(char*)&m_Pack,sizeof(m_Pack),0))
		return FALSE;
	//==================================================
	// Stmt 확인.
	//==================================================
	if(( m_Pack.nIndex < 0 ) || ( m_Pack.nIndex >= STMT_SVRCOUNT))
	{
		m_nCurIndex = STMT_COUNT;
	}
	else
	{
		m_nCurIndex = m_Pack.nIndex;
	}
	//==================================================
	// 만약에, 프로토콜이 NULL이라면, 새로 생성 한다.
	//==================================================
	if ( NULL == m_stmt[m_nCurIndex])
	{
		m_stmt[m_nCurIndex] = new STMT_SERVER;
		m_stmt[m_nCurIndex]->m_pStmt = NULL;
		m_stmt[m_nCurIndex]->m_pszError = NULL;
		memset(m_stmt[m_nCurIndex]->m_szSQL,0,4098);
		m_stmt[m_nCurIndex]->m_nSize = 0;
		m_stmt[m_nCurIndex]->m_nRow = 0;
		m_stmt[m_nCurIndex]->m_nCol = 0;
		m_stmt[m_nCurIndex]->m_bIsEnd = TRUE; // Fetch시에 데이터의 끝에 도달 했는지에 대한 플래그.
		memset(m_stmt[m_nCurIndex]->m_szError,0,1024);
		m_stmt[m_nCurIndex]->m_nRemain = 0;
		m_stmt[m_nCurIndex]->m_nColIndex = 0;
		m_stmt[m_nCurIndex]->m_nUseSize = 0;
	}
	//==================================================
	// 명령에 따른 Procedure 시작.
	//==================================================
	switch(m_Pack.nItem)
	{
	case ITEM_LOGIN:
		{
			LogInProcedure();
			break;
		}
	case ITEM_SELECT:
		{
			SelectProcedure();
			break;
		}
	case ITEM_EXECUTE:
		{
			ExecuteProcedure();
			break;
		}
	case ITEM_BEGIN:
		{
			BeginProcedure();
			break;
		}
	case ITEM_COMMIT:
		{
			CommitProcedure();
			break;
		}
	case ITEM_ROLLBACK:
		{
			RollBackProcedure();
			break;
		}
	case ITEM_COLUMNCOUNT:
		{
			ColumnCountProcedure();
			break;
		}
	case ITEM_COLUMNNAME:
		{
			ColumnNameProcedure();
			break;
		}
	case ITEM_COLUMNINFO:
		{
			ColumnInfoProcedure();
			break;
		}
	case ITEM_RECOUNT:
		{
			RecordCountProcedure();
			break;
		}
		
	case ITEM_FETCH:
	case ITEM_MOVENEXT:
		{
			FetchProcedure();
			break;
		}
	case ITEM_VALUE:
		{
			break;
		}
	case ITEM_MOVEPREV:
		{
			break;
		}
	case ITEM_MOVEFIRST:
		{
			break;
		}
	case ITEM_MOVELAST:
		{
			break;
		}
	case ITEM_CHECKLIVE:
		{
			CheckLiveProcedure();
			break;
		}
	case ITEM_BINDPARAM_COUNT:
		{
			BindParameterCountProcedure();
			break;
		}
	case ITEM_PREPARE:
		{
			break;
		}
	case ITEM_STEP:
		{
			break;
		}
	case ITEM_READ_SELECT:
		{
			break;
		}
	case ITEM_READ_COLUMNCOUNT:  
		{
			break;
		}
	case ITEM_READ_COLUMNNAME: 
		{
			break;
		}
	case ITEM_READ_COLUMNINFO:  
		{
			break;
		}
	case ITEM_READ_RECOUNT:  
		{
			break;
		}
	case ITEM_READ_FETCH:  
		{
			break;
		}
	case ITEM_READ_BINDPARAM_COUNT:  
		{
			break;
		}
	case ITEM_USERFUNC:
		{
			UserFuncProcedure();
			break;
		}
	}
	return TRUE;
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 데이터를 받았을때 프로토콜에 따라서 수행되는 진행 함수.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 로그인 프로시저 - 현재 쓰이지 않는다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::LogInProcedure()
{
	SFUNC()
	LOG_INFO info;
	memset(&info,0,sizeof(LOG_INFO));
	memcpy(&info,m_Pack.szData,sizeof(LOG_INFO));
	STRCPY(m_szUser,info.szUID,30);
	m_nAuth = info.nAuth;
	info.nAuth = AUTH_ADMIN;
	/*	
	//==================================================
	/// 조회 시작.
	//==================================================
	sqlite3_stmt *pstmt;
	if(SQLITE_OK != sqlite3_prepare( pSQLite, szSQL, (int)strlen(szSQL)+1, &pstmt,NULL))
	{
		CString sMsg(sqlite3_errmsg(pSQLite));
		SetResult(sMsg);
		sqlite3_finalize(pstmt);
		sqlite3_close(pSQLite);
		return;
	}
	*/
	WriteSock(ITEM_LOGIN, STAT_END,REPLY_CLIENT_OK, sizeof(LOG_INFO), (char*)&info);		
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Select 에 대응.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::SelectProcedure()
{
	SFUNC()
	switch(m_Pack.nStat)
	{
	case STAT_START:
		{
			if(REPLY_SERVER_INITIAL == m_Pack.nReply)
			{
				memset(m_stmt[m_nCurIndex]->m_szSQL,0,4098);
				m_stmt[m_nCurIndex]->m_nSize = 0;
			}
			AddSQL();
			WriteSock(ITEM_SELECT, STAT_END, REPLY_CLIENT_OK, strlen("SELECT_NEXT"), "SELECT_NEXT");
			break;
		}
	case STAT_CONTINUE:
		{
			AddSQL();
			WriteSock(ITEM_SELECT, STAT_END, REPLY_CLIENT_OK, strlen("SELECT_NEXT"), "SELECT_NEXT");
			break;
		}
	case  STAT_END:
		{
			if(REPLY_SERVER_INITIAL == m_Pack.nReply)
			{
				memset(m_stmt[m_nCurIndex]->m_szSQL,0,4098);
				m_stmt[m_nCurIndex]->m_nSize = 0;
			}
			AddSQL();
			if (TRUE == SelectPrepare(m_stmt[m_nCurIndex]->m_szSQL))
			{
				m_stmt[m_nCurIndex]->m_nRemain = 0;
				m_stmt[m_nCurIndex]->m_nColIndex = 0;
				m_stmt[m_nCurIndex]->m_nUseSize = 0;
				WriteSock(ITEM_SELECT, STAT_END, REPLY_CLIENT_OK, strlen("SELECT_OK"), "SELECT_OK");
			}
			else
			{
				WriteSock(ITEM_SELECT, STAT_END, REPLY_CLIENT_FAIL, strlen(m_stmt[m_nCurIndex]->m_szError), m_stmt[m_nCurIndex]->m_szError);
			}
			break;
		}
	}
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// User Function 수행.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::UserFuncProcedure()
{
	SFUNC()
	switch(m_Pack.nStat)
	{
	case STAT_START:
		{
			if(REPLY_SERVER_INITIAL == m_Pack.nReply)
			{
				memset(m_stmt[m_nCurIndex]->m_szSQL,0,4098);
				m_stmt[m_nCurIndex]->m_nSize = 0;
			}
			AddSQL();
			WriteSock(ITEM_SELECT, STAT_END, REPLY_CLIENT_OK, strlen("USERFUNC_NEXT"), "USERFUNC_NEXT");
			break;
		}
	case STAT_CONTINUE:
		{
			AddSQL();
			WriteSock(ITEM_SELECT, STAT_END, REPLY_CLIENT_OK, strlen("USERFUNC_NEXT"), "USERFUNC_NEXT");
			break;
		}
	case  STAT_END:
		{
			if(REPLY_SERVER_INITIAL == m_Pack.nReply)
			{
				memset(m_stmt[m_nCurIndex]->m_szSQL,0,4098);
				m_stmt[m_nCurIndex]->m_nSize = 0;
			}
			AddSQL();
			if (TRUE == SelectUserFunc(m_stmt[m_nCurIndex]->m_szSQL))
			{
				m_stmt[m_nCurIndex]->m_nRemain = 0;
				m_stmt[m_nCurIndex]->m_nColIndex = 0;
				m_stmt[m_nCurIndex]->m_nUseSize = 0;
				WriteSock(ITEM_USERFUNC, STAT_END, REPLY_CLIENT_OK, strlen("USERFUNC_OK"), "USERFUNC_OK");
			}
			else
			{
				WriteSock(ITEM_USERFUNC, STAT_END, REPLY_CLIENT_FAIL, strlen(m_stmt[m_nCurIndex]->m_szError), m_stmt[m_nCurIndex]->m_szError);
			}
			break;
		}
	}
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 실행 함수 수행.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::ExecuteProcedure()
{
	SFUNC()
	switch(m_Pack.nStat)
	{
	case STAT_START:
		{
			memset(m_stmt[m_nCurIndex]->m_szSQL,0,4098);
			m_stmt[m_nCurIndex]->m_nSize = 0;
			AddSQL();
			WriteSock(ITEM_EXECUTE, STAT_END, REPLY_CLIENT_OK, strlen("EXECUTE_NEXT"), "EXECUTE_NEXT");
			break;
		}
	case STAT_CONTINUE:
		{
			AddSQL();
			WriteSock(ITEM_EXECUTE, STAT_END, REPLY_CLIENT_OK, strlen("EXECUTE_NEXT"), "EXECUTE_NEXT");
			break;
		}
	case  STAT_END:
		{
			if(REPLY_SERVER_INITIAL == m_Pack.nReply)
			{
				memset(m_stmt[m_nCurIndex]->m_szSQL,0,4098);
				m_stmt[m_nCurIndex]->m_nSize = 0;
			}
			AddSQL();
			m_stmt[m_nCurIndex]->m_szSQL[4096] = 0;
			if (TRUE == ExecuteSQL(m_stmt[m_nCurIndex]->m_szSQL))
			{

				WriteSock(ITEM_EXECUTE, STAT_END, REPLY_CLIENT_OK, strlen("EXECUTE_OK"), "EXECUTE_OK");
			}
			else
			{
				WriteSock(ITEM_EXECUTE, STAT_END, REPLY_CLIENT_FAIL, strlen(m_stmt[m_nCurIndex]->m_szError), 
					m_stmt[m_nCurIndex]->m_szError);
			}
			break;
		}
	}
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 레코드 카운트 실제적으로 쓰이지않는다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::RecordCountProcedure()
{
	SFUNC()
	char szData[10];
	memset(szData,'\0',10);
	memcpy(szData,&m_stmt[m_nCurIndex]->m_nRow,sizeof(int));
	WriteSock(ITEM_RECOUNT, STAT_END,REPLY_CLIENT_OK,sizeof(int), szData);		
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Select 후에 컬럼 숫자.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::ColumnCountProcedure()
{
	SFUNC()
	char szData[10];
	memset(szData,'\0',10);
	memcpy(szData,&m_stmt[m_nCurIndex]->m_nCol,sizeof(short));
	WriteSock(ITEM_COLUMNCOUNT, STAT_END,REPLY_CLIENT_OK,sizeof(short), szData);		
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 컬럼 Name ==> 실제로는 쓰이지 않는다. Column Info에서 처리.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::ColumnNameProcedure()
{
	SFUNC()
	if ( ( m_Pack.szData[0] >= m_stmt[m_nCurIndex]->m_nCol)||(m_Pack.szData[0] < 0 ))
	{
		WriteSock(ITEM_COLUMNNAME, STAT_END,REPLY_CLIENT_FAIL,strlen("INDEX_ERROR"), "INDEX_ERROR");		
		return;
	}
	
	const char* pszTemp = sqlite3_column_name( m_stmt[m_nCurIndex]->m_pStmt, m_Pack.szData[0]);
	
	WriteSock(ITEM_COLUMNNAME, STAT_END,REPLY_CLIENT_OK,strlen(pszTemp), pszTemp);		
	return;
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 컬럼에 대한 정보를 보낸다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::ColumnInfoProcedure()
{
	SFUNC()
	if ( ( m_Pack.szData[0] >= m_stmt[m_nCurIndex]->m_nCol)||(m_Pack.szData[0] < 0 ))
	{
		WriteSock(ITEM_COLUMNINFO, STAT_END,REPLY_CLIENT_FAIL,strlen("INDEX_ERROR"), "INDEX_ERROR");		
		return;
	}
	COLUMN_INFO info;
	memset(&info,'\0',sizeof(COLUMN_INFO));

	int nCol = m_Pack.szData[0];
	int nn = 0, pk = 0, ai = 0;
    const char *zDbName, *zTableName, *zColumnName, *pzDataType, *pzCollSeq;
	
	zDbName = sqlite3_column_database_name(m_stmt[m_nCurIndex]->m_pStmt, nCol);
    zTableName = sqlite3_column_table_name(m_stmt[m_nCurIndex]->m_pStmt, nCol);
	zColumnName = 	sqlite3_column_name(m_stmt[m_nCurIndex]->m_pStmt, nCol);
    sqlite3_table_column_metadata(m_pRead, zDbName, zTableName, zColumnName,
				  &pzDataType, &pzCollSeq, &nn, &pk, &ai);
	info.bAutoInc = ai>0?TRUE:FALSE;
	info.bNotNULL = nn>0?TRUE:FALSE;
	info.bPriKey = pk>0?TRUE:FALSE;
	if( NULL != zDbName)
		STRCPY(info.szDbName,zDbName,128);
	if( NULL != zTableName)
		STRCPY(info.szTableName,zTableName,128);
	if( NULL != zColumnName)
		STRCPY(info.szColumnName,zColumnName,128);
	if( NULL != pzCollSeq)
		STRCPY(info.szCollSeq,pzCollSeq,128);
    char *ptypename = (char *) sqlite3_column_decltype(m_stmt[m_nCurIndex]->m_pStmt, nCol);
	if( ptypename != NULL)
		memcpy(info.szTypename,ptypename,min(127,strlen(ptypename)));
	
	WriteSock(ITEM_COLUMNINFO, STAT_END,REPLY_CLIENT_OK,sizeof(COLUMN_INFO),(char*)&info);		
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Move_next 및 Step 및 Fetch에 대응 하는 프로시저.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::FetchProcedure()
{
	SFUNC()
	int nFillSize = 0;
	int nCpySize =0;
	int nSize;
	char c;
	static char szTemp[DATA_SIZE +1];
	RESETPACK(m_Pack);
	m_stmt[m_nCurIndex]->m_bIsEnd = FALSE;
	while(TRUE)
	{
		if(nFillSize >= DATA_SIZE)
		{
			break;
		}
		if( m_stmt[m_nCurIndex]->m_nRemain > 0 )
		{
			nCpySize = (DATA_SIZE - nFillSize) > m_stmt[m_nCurIndex]->m_nRemain?m_stmt[m_nCurIndex]->m_nRemain:(DATA_SIZE - nFillSize);
			memcpy(m_Pack.szData+nFillSize, m_stmt[m_nCurIndex]->m_pszValue + m_stmt[m_nCurIndex]->m_nUseSize , nCpySize);
			m_stmt[m_nCurIndex]->m_nRemain -= nCpySize;
			m_stmt[m_nCurIndex]->m_nUseSize += nCpySize;
			nFillSize += nCpySize;
			continue;
		}
		if(m_stmt[m_nCurIndex]->m_nColIndex <= 0)
		{
			
			if(sqlite3_step( m_stmt[m_nCurIndex]->m_pStmt ) != SQLITE_ROW )
			{
				
				m_stmt[m_nCurIndex]->m_bIsEnd = TRUE;
				break;
			}
			m_stmt[m_nCurIndex]->m_bIsEnd = FALSE;
			
		}
		
		c = sqlite3_column_type( m_stmt[m_nCurIndex]->m_pStmt,m_stmt[m_nCurIndex]->m_nColIndex);
		m_stmt[m_nCurIndex]->m_pszValue = 
		(const char*)sqlite3_column_text( m_stmt[m_nCurIndex]->m_pStmt,m_stmt[m_nCurIndex]->m_nColIndex);
		
		m_stmt[m_nCurIndex]->m_nRemain = 0;
		m_stmt[m_nCurIndex]->m_nUseSize = 0;
		 
		if(( NULL == m_stmt[m_nCurIndex]->m_pszValue) || ( strlen(m_stmt[m_nCurIndex]->m_pszValue) <= 0 ))
		{
			m_stmt[m_nCurIndex]->m_pszValue = SPACECHAR;
			nSize = 2;
		}
		else
		{
			nSize = strlen(m_stmt[m_nCurIndex]->m_pszValue) + 2;
		}
		nCpySize = (DATA_SIZE - nFillSize) > nSize ? nSize :(DATA_SIZE - nFillSize);
		if( nCpySize < nSize)
		{
			// nSize : 11 , nCpySize : 4  remain  = 7 : use :3   실제 크기 : 10
			// nsize : 11,  nCpySize : 3  remain  = 8 : use :2   실제 크기 : 10
			m_stmt[m_nCurIndex]->m_nRemain = nSize - nCpySize;
			m_stmt[m_nCurIndex]->m_nUseSize += nCpySize - 1;
		}
		m_stmt[m_nCurIndex]->m_nColIndex =  (m_stmt[m_nCurIndex]->m_nColIndex + 1) >= m_stmt[m_nCurIndex]->m_nCol ? 0:(m_stmt[m_nCurIndex]->m_nColIndex + 1);
		memcpy(m_Pack.szData + nFillSize, &c, 1);
		memcpy(m_Pack.szData + nFillSize + 1, m_stmt[m_nCurIndex]->m_pszValue,nCpySize  - 1);
		nFillSize += nCpySize;
	}
	m_Pack.nItem = ITEM_FETCH;
	if(( 0 == m_stmt[m_nCurIndex]->m_nColIndex ) && ( m_stmt[m_nCurIndex]->m_nRemain <= 0 ))
		m_Pack.nStat = STAT_END;
	else
		m_Pack.nStat = STAT_CONTINUE;
	m_Pack.nDataLen = nFillSize;
	if(TRUE == m_stmt[m_nCurIndex]->m_bIsEnd )
	{
		m_Pack.nReply = REPLY_CLIENT_END;
	}
	else
	{
		m_Pack.nReply = REPLY_CLIENT_NOTEND;
	}
	m_opTime = time(NULL);
	SEND(m_sock, (char*)&m_Pack,  sizeof(PACKET_STRT) , 0);
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// 외부에서 서버의 건강성 체크를 이한 것. Select 문장을 수행 해 본다.(user_info_tbl은 필수 Table임)
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::CheckLiveProcedure()
{
	SFUNC()
	char szSQL[100];
	memset(szSQL,0,100);
	sprintf_s(szSQL,100,"SELECT COUNT(*) FROM USER_INFO_TBL");
	if( TRUE == SelectPrepare(szSQL)) 
	{
		m_stmt[m_nCurIndex]->m_nCol = sqlite3_column_count( m_stmt[m_nCurIndex]->m_pStmt );
		WriteSock(ITEM_CHECKLIVE, STAT_END,REPLY_CLIENT_OK,strlen("CHECK_LIVE_OK"), "CHECK_LIVE_OK");		
	}
	else
	{
		const char* pErr =  sqlite3_errmsg(m_pRead);
		if( pErr != NULL)
		{
			WriteSock(ITEM_CHECKLIVE, STAT_END,REPLY_CLIENT_FAIL,strlen(pErr), pErr);		
		}
		else
		{
			WriteSock(ITEM_CHECKLIVE, STAT_END,REPLY_CLIENT_FAIL,strlen("CHECK_LIVE_FAIL"), "CHECK_LIVE_FAIL");		
		}
	}
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Begin 프로시저 ==> 자동 Begin이라서 그냥 OK한다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::BeginProcedure()
{
	SFUNC()
	int ret = SQLITE_OK;
	SFREE(m_stmt[m_nCurIndex]->m_pszError);
	if (SQLITE_OK == ret)
	{
		WriteSock(ITEM_BEGIN, STAT_END, REPLY_CLIENT_OK, strlen("BEGIN_OK"), "BEGIN_OK");
	}
	else
	{
		WriteSock(ITEM_BEGIN, STAT_END, REPLY_CLIENT_FAIL, strlen(m_stmt[m_nCurIndex]->m_szError), m_stmt[m_nCurIndex]->m_szError);
	}
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Commit 프로시저. ==> Comit을 호출하면, Commit을 수행 한다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::CommitProcedure()
{
	SFUNC()
	int ret = SQLITE_OK;
	SFREE(m_stmt[m_nCurIndex]->m_pszError)
	m_bBegin = gDoCommit();
	if (SQLITE_OK == ret)
	{
		WriteSock(ITEM_COMMIT, STAT_END, REPLY_CLIENT_OK, strlen("COMMIT_OK"), "COMMIT_OK");
	}
	else
	{
		WriteSock(ITEM_COMMIT, STAT_END, REPLY_CLIENT_FAIL, strlen(m_stmt[m_nCurIndex]->m_szError), m_stmt[m_nCurIndex]->m_szError);
	}
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// RollBack은지원 하지 않는다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::RollBackProcedure()
{
	SFUNC()
	WriteSock(ITEM_ROLLBACK, STAT_END, REPLY_CLIENT_FAIL, strlen("ROLLBACK_NOT_WORKING"),"ROLLBACK_NOT_WORKING");
}
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
// Bind Parameter는 지원 하지 않으나,정보만 보낸다.
//▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬▬
void CSocketDB::BindParameterCountProcedure()
{
	SFUNC()
	char szData[10];
	memset(szData,'\0',10);
	int nCount = 0;
	if( NULL != m_stmt[m_nCurIndex]->m_pStmt)
	{
		nCount = sqlite3_bind_parameter_count(m_stmt[m_nCurIndex]->m_pStmt);
	}
	memcpy(szData,&nCount,sizeof(int));
	WriteSock(ITEM_BINDPARAM_COUNT, STAT_END,REPLY_CLIENT_OK,sizeof(int),szData);		
}
